const Hook = require('./Hook.js')

// 工厂类HookCodeFactory
class HookCodeFactory {
    
    args({before, after} = {}){
        let allArgs = this.options.args
        if(before) allArgs = [before].concat(allArgs)
        if(after) allArgs = allArgs.concat([after])
        return allArgs.join(', ')
    }

    head(){
        return `"use strict";var _context;var _x = this._x;`
    }

    content(){
        let code = `var _counter = ${this.options.taps.length};var _done = (function () {
            _callback();
        });`
        for(let i = 0; i<this.options.taps.length; i++){
            code += `var _fn${i} = _x[${i}];  _fn${i}(${this.args()}, (function () {
                if (--_counter === 0) _done();
            }));`
        }
        return code
    }

    setup(instance, options){ // 先准备后续需要使用到的数据
        this.options = options // 这里的操作在源码中是通过 init 方法实现， 而我们当前是直接挂在 this 身上
        instance._x = options.taps.map(v=> v.fn) // this._x = [fn1, fn2, ...]
    }

    create(options){ // 核心就是创建一段可执行代码然后返回
        let fn //  fn = new Function("name, age", "var _x = this._x, var _fn0 = _x[0]; _fn0(name, age);")
        fn = new Function(
            this.args({after: '_callback'}),
            this.head() + this.content()
        )
        return fn
    }
}

const factory = new HookCodeFactory()

class AsyncParallelHook extends Hook {
    constructor(args){
        super(args)
    }
    compile(options){ // {taps: [{}, {}], args: [name, age] }
        factory.setup(this, options)
        return factory.create(options)
    }
}

module.exports = AsyncParallelHook